Skip to main content
Glama

Karakeep MCP server

by karakeep-app
info.tsx8.4 kB
import React from "react"; import { Alert, Pressable, View } from "react-native"; import { KeyboardAwareScrollView, KeyboardGestureArea, } from "react-native-keyboard-controller"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { router, Stack, useLocalSearchParams } from "expo-router"; import TagPill from "@/components/bookmarks/TagPill"; import FullPageError from "@/components/FullPageError"; import { Button } from "@/components/ui/Button"; import ChevronRight from "@/components/ui/ChevronRight"; import { Divider } from "@/components/ui/Divider"; import FullPageSpinner from "@/components/ui/FullPageSpinner"; import { Input } from "@/components/ui/Input"; import { Skeleton } from "@/components/ui/Skeleton"; import { Text } from "@/components/ui/Text"; import { useToast } from "@/components/ui/Toast"; import { cn } from "@/lib/utils"; import { useAutoRefreshingBookmarkQuery, useDeleteBookmark, useUpdateBookmark, } from "@karakeep/shared-react/hooks/bookmarks"; import { BookmarkTypes, ZBookmark } from "@karakeep/shared/types/bookmarks"; import { isBookmarkStillTagging } from "@karakeep/shared/utils/bookmarkUtils"; function InfoSection({ className, ...props }: React.ComponentProps<typeof View>) { return ( <View className={cn("flex gap-2 rounded-lg bg-card p-3", className)} {...props} /> ); } function TagList({ bookmark }: { bookmark: ZBookmark }) { return ( <InfoSection> {isBookmarkStillTagging(bookmark) ? ( <View className="flex gap-4 pb-3"> <Skeleton className="h-4 w-full" /> <Skeleton className="h-4 w-full" /> </View> ) : ( bookmark.tags.length > 0 && ( <> <View className="flex flex-row flex-wrap gap-2 rounded-lg p-2"> {bookmark.tags.map((t) => ( <TagPill key={t.id} tag={t} /> ))} </View> <Divider orientation="horizontal" /> </> ) )} <View> <Pressable onPress={() => router.push(`/dashboard/bookmarks/${bookmark.id}/manage_tags`) } className="flex w-full flex-row justify-between gap-3" > <Text>Manage Tags</Text> <ChevronRight /> </Pressable> </View> </InfoSection> ); } function ManageLists({ bookmark }: { bookmark: ZBookmark }) { return ( <InfoSection> <View> <Pressable onPress={() => router.push(`/dashboard/bookmarks/${bookmark.id}/manage_lists`) } className="flex w-full flex-row justify-between gap-3 rounded-lg" > <Text>Manage Lists</Text> <ChevronRight /> </Pressable> </View> </InfoSection> ); } function TitleEditor({ title, setTitle, isPending, }: { title: string | null | undefined; setTitle: (title: string | null) => void; isPending: boolean; }) { return ( <InfoSection> <Input editable={!isPending} multiline={false} numberOfLines={1} placeholder="Title" onChangeText={(text) => setTitle(text)} defaultValue={title ?? ""} /> </InfoSection> ); } function NotesEditor({ notes, setNotes, isPending, }: { notes: string | null | undefined; setNotes: (title: string | null) => void; isPending: boolean; }) { return ( <InfoSection> <Input editable={!isPending} multiline={true} placeholder="Notes" inputClasses="h-24" onChangeText={(text) => setNotes(text)} textAlignVertical="top" defaultValue={notes ?? ""} /> </InfoSection> ); } const ViewBookmarkPage = () => { const insets = useSafeAreaInsets(); const { slug } = useLocalSearchParams(); const { toast } = useToast(); if (typeof slug !== "string") { throw new Error("Unexpected param type"); } const { mutate: editBookmark, isPending: isEditPending } = useUpdateBookmark({ onSuccess: () => { toast({ message: "The bookmark has been updated!", showProgress: false, }); setEditedBookmark({}); }, }); const { mutate: deleteBookmark, isPending: isDeletionPending } = useDeleteBookmark({ onSuccess: () => { router.replace("dashboard"); toast({ message: "The bookmark has been deleted!", showProgress: false, }); }, }); const { data: bookmark, isPending, refetch, } = useAutoRefreshingBookmarkQuery({ bookmarkId: slug, }); const [editedBookmark, setEditedBookmark] = React.useState<{ title?: string | null; note?: string; }>({}); if (isPending) { return <FullPageSpinner />; } if (!bookmark) { return ( <FullPageError error="Bookmark not found" onRetry={() => refetch()} /> ); } const handleDeleteBookmark = () => { Alert.alert( "Delete bookmark?", "Are you sure you want to delete this bookmark?", [ { text: "Cancel", style: "cancel" }, { text: "Delete", onPress: () => deleteBookmark({ bookmarkId: bookmark.id }), style: "destructive", }, ], ); }; const onDone = () => { const doDone = () => { if (router.canGoBack()) { router.back(); } else { router.replace("dashboard"); } }; if (Object.keys(editedBookmark).length === 0) { doDone(); return; } Alert.alert("You have unsaved changes", "Do you still want to leave?", [ { text: "Cancel", style: "cancel" }, { text: "Leave", onPress: doDone, }, ]); }; let title = null; switch (bookmark.content.type) { case BookmarkTypes.LINK: title = bookmark.title ?? bookmark.content.title; break; case BookmarkTypes.TEXT: title = bookmark.title; break; case BookmarkTypes.ASSET: title = bookmark.title ?? bookmark.content.fileName; break; } return ( <KeyboardGestureArea interpolator="ios"> <KeyboardAwareScrollView className="p-4" bottomOffset={8} keyboardDismissMode="interactive" contentContainerStyle={{ paddingBottom: insets.bottom }} > <Stack.Screen options={{ headerShown: true, headerTransparent: false, headerTitle: title ?? "Untitled", headerRight: () => ( <Pressable onPress={onDone}> <Text>Done</Text> </Pressable> ), }} /> <View className="gap-4"> <TitleEditor title={title} setTitle={(title) => setEditedBookmark((prev) => ({ ...prev, title })) } isPending={isEditPending} /> <TagList bookmark={bookmark} /> <ManageLists bookmark={bookmark} /> <NotesEditor notes={bookmark.note} setNotes={(note) => setEditedBookmark((prev) => ({ ...prev, note: note ?? "" })) } isPending={isEditPending} /> <View className="flex justify-between gap-3"> <Button onPress={() => editBookmark({ bookmarkId: bookmark.id, ...editedBookmark, }) } disabled={isEditPending} > <Text>Save</Text> </Button> <Button variant="destructive" onPress={handleDeleteBookmark} disabled={isDeletionPending} > <Text>Delete</Text> </Button> </View> <View className="gap-2"> <Text className="items-center text-center"> Created {bookmark.createdAt.toLocaleString()} </Text> {bookmark.modifiedAt && bookmark.modifiedAt.getTime() !== bookmark.createdAt.getTime() && ( <Text className="items-center text-center"> Modified {bookmark.modifiedAt.toLocaleString()} </Text> )} </View> </View> </KeyboardAwareScrollView> </KeyboardGestureArea> ); }; export default ViewBookmarkPage;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/karakeep-app/karakeep'

If you have feedback or need assistance with the MCP directory API, please join our Discord server